package eu.vranckaert.workRegistrationWidget.activities;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.*;
import android.widget.ExpandableListView;
import android.widget.SimpleExpandableListAdapter;
import com.google.inject.Inject;
import eu.vranckaert.workRegistrationWidget.R;
import eu.vranckaert.workRegistrationWidget.domain.TimeRegistration;
import eu.vranckaert.workRegistrationWidget.service.RegistrationService;
import eu.vranckaert.workRegistrationWidget.service.WidgetLayoutBuilderService;
import eu.vranckaert.workRegistrationWidget.util.DateUtil;
import eu.vranckaert.workRegistrationWidget.util.WidgetUpdater;
import roboguice.activity.GuiceExpandableListActivity;

import java.util.*;

/**
 * @author Dirk Vranckaert
 * Date: 2-mei-2010
 * Time: 16:14:01
 */
public class ResultsActivity extends GuiceExpandableListActivity {
    private static final String LOG_TAG = ResultsActivity.class.getName();

    @Inject
    RegistrationService registrationService;

    @Inject
    WidgetLayoutBuilderService widgetLayoutBuilderService;

    /*
     * Dialog vars
     */
    private static final int DIALOG_LOADING = 0;
    private static final int DIALOG_REMOVE_ALL_REGS = 1;
    private static final int DIALOG_REMOVE_REG = 2;
    private static final int DIALOG_SD_READ_ONLY = 3;
    private static final int DIALOG_NO_SD = 4;

    /*
     * Context menu vars
     */
    private static final int CONTEXT_MAN_MENU_REG_EDIT = -10000;
    private static final int CONTEXT_MAN_MENU_REG_MAP_START_LOC = -20000;
    private static final int CONTEXT_MAN_MENU_REG_MAP_END_LOC = -30000;
    private static final int CONTEXT_MAN_MENU_REG_DELETE = -40000;

    /*
     * Intent vars
     */
    private static final int EDIT_ACTIVITY_REQUEST_CODE = 0;
    private static final int ADD_CUSTOM_ACTIVITY_REQUEST_CODE = 1;

    /*
     * Bundle vars
     */
    private String BUNDLE_REGISTRATIONS = "registrations";

    private List<TimeRegistration> timeRegistrations = new ArrayList<TimeRegistration>();
    private SimpleExpandableListAdapter registrationAdapter;
    private List<TimeRegistration> registrationsGroup;
    private TimeRegistration selectedRegistration = null;
    private Context context = this;
    private ResultsActivity activity = this;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        //Init
        super.onCreate(savedInstanceState);
        Log.d(LOG_TAG, "About to create content view");
        setContentView(R.layout.registration_results);
        registerForContextMenu(getExpandableListView());

        if (savedInstanceState != null && savedInstanceState.getSerializable(BUNDLE_REGISTRATIONS) != null) {
            Log.d(LOG_TAG, "Time registrations found from preivous state!");
            timeRegistrations = (ArrayList<TimeRegistration>) savedInstanceState.getSerializable(BUNDLE_REGISTRATIONS);
            for(TimeRegistration timeRegistration : timeRegistrations) {
                timeRegistration.clearExpandableList();
            }
            savedInstanceState.remove(BUNDLE_REGISTRATIONS);
        }
        
        if(timeRegistrations == null || timeRegistrations.size() == 0) {
            Log.d(LOG_TAG, "Registrations not reloaded from any previous state!");
            loadRegistrations();
        } else {
            Log.d(LOG_TAG, timeRegistrations.size() + "registrations reloaded from previous state!");
            updateRegistrationAdapater();
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        Log.d(LOG_TAG, "Time registrations about to be added on the saved instance!");
        ArrayList<TimeRegistration> registrations = (ArrayList<TimeRegistration>)timeRegistrations;
        outState.putSerializable(BUNDLE_REGISTRATIONS, registrations);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onDestroy() {
        Log.d(LOG_TAG, "Coming in on destroy method!!");
        this.dismissDialog(DIALOG_LOADING);
        super.onDestroy();
    }

    private void loadRegistrations() {
        AsyncTask<Void, Void, Void> loadRegistrationsAsyncTask = new AsyncTask() {
            @Override
            protected void onPreExecute() {
                activity.showDialog(DIALOG_LOADING);
            }

            @Override
            protected void onPostExecute(Object o) {
                updateRegistrationAdapater();
                activity.dismissDialog(DIALOG_LOADING);
            }

            @Override
            protected Long doInBackground(Object... objects) {
                timeRegistrations = registrationService.getAllTimeRegistrations(getApplicationContext());
                context = getApplicationContext();
                return 100L;
            }
        };
        loadRegistrationsAsyncTask.execute();
    }

    private void updateRegistrationAdapater() {
        registrationAdapter = new SimpleExpandableListAdapter(
            context,
            createGroups(),
            R.layout.registration_result_item_group,
            new String[] {"registratonDate"},
            new int[] {R.id.registrationDate},
            createChilds(),
            R.layout.registration_result_item_child,
            new String[] {"registratoinTime", "registrationDuration"},
            new int[] {R.id.registrationTime, R.id.registrationDuration}
        );
        setListAdapter(registrationAdapter);
        registrationAdapter.notifyDataSetChanged();
    }

    private List<? extends List<? extends Map<String, ?>>> createChilds() {

        List subList = new ArrayList();
        for (TimeRegistration timeRegistration : registrationsGroup) {
            List subListSecondLvl = new ArrayList();
            for (TimeRegistration reg : timeRegistration.getExpandableList()) {
                String registrationTimeValue = DateUtil.formatTime(reg.getStartDate(), this);
                String registrationDurationValue = getString(R.string.defaultDuration);

                String duration = "";
                if (reg.getEndDate().getTime() != 0L) {
                    String endDateValue = DateUtil.formatTime(reg.getEndDate(), this);
                    registrationTimeValue += " - " + endDateValue;

                    duration = DateUtil.calculateDurationInTimeFormat(reg.getStartDate(), reg.getEndDate());
                } else {
                    registrationTimeValue += " - " + this.getString(R.string.now);
                    duration = DateUtil.calculateDurationInTimeFormat(reg.getStartDate(), new Date());
                }

                if (duration.equals("ERROR")) {
                    duration = getString(R.string.durationError);
                }
                registrationDurationValue = getString(R.string.durationLabel) + " " + duration;

                HashMap map = new HashMap();
                map.put("registratoinTime", registrationTimeValue);
                map.put("registrationDuration", registrationDurationValue);
                subListSecondLvl.add(map);
            }
            subList.add(subListSecondLvl);
        }

        return subList;
    }

    private List<? extends Map<String, ?>> createGroups() {
        registrationsGroup = new ArrayList<TimeRegistration>();

        List<String> registrations = new ArrayList<String>();
        for(TimeRegistration registration : timeRegistrations) {
            String date = DateUtil.formatDateFull(registration.getStartDate(), this);
            if (!registrations.contains(date)) {
                registrations.add(date);
                registrationsGroup.add(registration);
            }
        }

        List output = new ArrayList();
        for (TimeRegistration timeRegistration : registrationsGroup) {
            for (TimeRegistration reg : timeRegistrations) {
                if(DateUtil.formatDate(reg.getStartDate(), this).equals(DateUtil.formatDate(timeRegistration.getStartDate(), this))) {
                    timeRegistration.addTimeRegistrationToExpandableList(reg);
                }
            }

            String registrationGroupHeader  = DateUtil.formatDateFull(timeRegistration.getStartDate(), this);
            //TODO check why there is sometimes some difference in the duration!!!
            //String dayTotal = DateUtil.calculateDayTotalsInTimeFormat(timeRegistration.getExpandableList());
            //registrationGroupHeader += (" (" + dayTotal + ")");
            HashMap map = new HashMap();
            map.put("registratonDate", registrationGroupHeader);
            output.add(map);
        }

        return output;
    }

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.resultsmenu, menu);
		return true;
	}

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
        int type = ExpandableListView.getPackedPositionType(info.packedPosition);

        if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
            int parentPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
            int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);

            TimeRegistration parentRegistration = registrationsGroup.get(parentPosition);
            TimeRegistration childRegistration = parentRegistration.getExpandableList().get(childPosition);

            String registrationTimeValue = DateUtil.formatTime(childRegistration.getStartDate(), this);
            if (childRegistration.getEndDate().getTime() != 0L) {
                String endDateValue = DateUtil.formatTime(childRegistration.getEndDate(), this);
                registrationTimeValue += " - " + endDateValue;
            } else {
                registrationTimeValue += " - " + this.getString(R.string.now);
            }
            menu.setHeaderTitle(DateUtil.formatDate(parentRegistration.getStartDate(), this) + "\n" + registrationTimeValue);

            /* Add menus based on which things are set in the child registration */
            menu.add(Menu.NONE, CONTEXT_MAN_MENU_REG_EDIT, Menu.NONE, R.string.regMenuEdit);
            menu.add(Menu.NONE, CONTEXT_MAN_MENU_REG_DELETE, Menu.NONE, R.string.regMenuDelete);
            if (childRegistration.getStartLatitude() != null && childRegistration.getStartLongtitude() != null) {
                menu.add(Menu.NONE, CONTEXT_MAN_MENU_REG_MAP_START_LOC, Menu.NONE, R.string.regMenuStartLocMap);
            }
            if (childRegistration.getEndLatitude() != null && childRegistration.getEndLongtitude() != null) {
                menu.add(Menu.NONE, CONTEXT_MAN_MENU_REG_MAP_END_LOC, Menu.NONE, R.string.regMenuEndLocMap);
            }

            //Only for test purpose
            //menu.add(Menu.NONE, CONTEXT_MAN_MENU_REG_MAP_START_LOC, Menu.NONE, "Dummy start-location");
            //menu.add(Menu.NONE, CONTEXT_MAN_MENU_REG_MAP_END_LOC, Menu.NONE, "Dummy end-location");
        }
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        Dialog dialog = null;
        switch (id) {
            case DIALOG_LOADING:
                ProgressDialog progressDialog = new ProgressDialog(this);
				progressDialog.setMessage(this.getString(R.string.loading));
                progressDialog.setCancelable(true); //TODO set to false if bug is fixed with going to landscape and loading bar that doesn't go away
				dialog = progressDialog;
				break;
            case DIALOG_REMOVE_ALL_REGS:
				AlertDialog.Builder alertRemoveAllRegs = new AlertDialog.Builder(this);
				alertRemoveAllRegs.setTitle(R.string.confirmation)
						   .setMessage(R.string.clearRegsAreYourSure)
						   .setCancelable(false)
						   .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									deleteAllRegistrations();
                                    dialog.cancel();
								}
							})
						   .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									dialog.cancel();
								}
							});
				dialog = alertRemoveAllRegs.create();
                break;
            case DIALOG_REMOVE_REG:
                AlertDialog.Builder alertRemoveReg = new AlertDialog.Builder(this);
				alertRemoveReg.setTitle(R.string.confirmation)
						   .setMessage(R.string.deleteRegAreYouSure)
						   .setCancelable(false)
						   .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									deleteRegistration();
                                    dialog.cancel();
								}
							})
						   .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									dialog.cancel();
								}
							});
				dialog = alertRemoveReg.create();
                break;
            case DIALOG_SD_READ_ONLY:
                AlertDialog.Builder alertSdReadOnly = new AlertDialog.Builder(this);
				alertSdReadOnly.setTitle(R.string.warning)
						   .setMessage(R.string.sdReadOnly)
						   .setCancelable(false)
						   .setNegativeButton(R.string.ok, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									dialog.cancel();
								}
							});
				dialog = alertSdReadOnly.create();
                break;
            case DIALOG_NO_SD:
                AlertDialog.Builder alertNoSd = new AlertDialog.Builder(this);
				alertNoSd.setTitle(R.string.warning)
						   .setMessage(R.string.noSdPresent)
						   .setCancelable(false)
						   .setNegativeButton(R.string.ok, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									dialog.cancel();
								}
							});
				dialog = alertNoSd.create();
                break;
        }

        return dialog;
    }

    @Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch(item.getItemId()) {
            case R.id.refresh:
                loadRegistrations();
                return true;
            case R.id.addManReg:
                Intent editActivity = new Intent(this.getApplicationContext(), CreateCustomRegistrationActivity.class);
                startActivityForResult(editActivity, ADD_CUSTOM_ACTIVITY_REQUEST_CODE);
                return true;
            case R.id.preferences:
                Intent preferencesActivity = new Intent(this.getApplicationContext(), PreferencesActivity.class);
                startActivity(preferencesActivity);
                return true;
            case R.id.export:
                startExport();
                return true;
            case R.id.clearRegs:
                showDialog(DIALOG_REMOVE_ALL_REGS);
                return true;
		}
		return false;
	}

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        String description;
        String title;

        ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo();
        int parentPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
        int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);

        TimeRegistration parentRegistration = registrationsGroup.get(parentPosition);
        TimeRegistration childRegistration = parentRegistration.getExpandableList().get(childPosition);

        switch(item.getItemId()) {
            case CONTEXT_MAN_MENU_REG_EDIT:
                Intent editActivity = new Intent(this.getApplicationContext(), EditRegistrationActivity.class);
                editActivity.putExtra("registration", childRegistration);
                startActivityForResult(editActivity, EDIT_ACTIVITY_REQUEST_CODE);
                return true;
            case CONTEXT_MAN_MENU_REG_DELETE:
                selectedRegistration = childRegistration;
                showDialog(DIALOG_REMOVE_REG);
                return true;
            case CONTEXT_MAN_MENU_REG_MAP_START_LOC:
                description = DateUtil.formatDateTimeInCurrentLocale(childRegistration.getStartDate(), this);
                title = getText(R.string.mapsTitleStartRegistration).toString();
                openMaps(new Double("4.2631566524505615"), new Double("50.75285017490387"), title, description); //Only for test purpose!
                //openMaps(childRegistration.getStartLongtitude(), childRegistration.getStartLatitude(), title, description);
                return true;
            case CONTEXT_MAN_MENU_REG_MAP_END_LOC:
                description = DateUtil.formatDateTimeInCurrentLocale(childRegistration.getEndDate(), this);
                title = getText(R.string.mapsTitleEndRegistration).toString();
                openMaps(new Double("4"), new Double("51"), null, description); //Only for test purpose!
                //openMaps(childRegistration.getEndLongtitude(), childRegistration.getEndLatitude(), title, description);
                return true;
        }
        return false;
    }

    private void openMaps(Double longtitude, Double latitude, String title, String description) {
        Intent mapsActivity = new Intent(this.getApplicationContext(), GoogleMapsActivity.class);
        mapsActivity.putExtra("longtitude", longtitude);
        mapsActivity.putExtra("latitude", latitude);
        mapsActivity.putExtra("title", title);
        mapsActivity.putExtra("description", description);
        startActivity(mapsActivity);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case EDIT_ACTIVITY_REQUEST_CODE:
                if (resultCode == RESULT_OK) {
                    Log.d(LOG_TAG, "Edit finished so reload the registrations!");
                    loadRegistrations();
                } else {
                    Log.d(LOG_TAG, "Edit not finished!");
                }
                break;
            case ADD_CUSTOM_ACTIVITY_REQUEST_CODE:
                if (resultCode == RESULT_OK) {
                    Log.d(LOG_TAG, "Custom registration added so reload the registrations!");
                    loadRegistrations();
                } else {
                    Log.d(LOG_TAG, "Custom registration adding not finished!");
                }
                break;
        }
    }

    private void deleteRegistration() {
        registrationService.removeRegistration(this, selectedRegistration);
        selectedRegistration = null;
        loadRegistrations();
        updateWidget();
    }

    private void deleteAllRegistrations() {
        registrationService.removeAllRegistrations(this);
        loadRegistrations();
        updateWidget();
    }

    private void startExport() {
        boolean isSdPresent = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
        boolean isSdReadOnly = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);

        if (isSdPresent && !isSdReadOnly) {
            Intent exportActivity = new Intent(this.getApplicationContext(), ExportActivity.class);
            startActivity(exportActivity);
        } else if (isSdReadOnly) {
            showDialog(DIALOG_SD_READ_ONLY);
        } else {
            showDialog(DIALOG_NO_SD);
        }
    }

    private void updateWidget() {
        TimeRegistration registration = registrationService.getLatestTimeRegistration(this);
        WidgetUpdater.updateWidget(this, registration, widgetLayoutBuilderService);
    }
}
